import json

import requests
from django.contrib.auth import login, logout, authenticate
from django.views import View
from django import http
from django_redis import get_redis_connection
from requests import post
from copy import deepcopy

from apps.app.models import User, Broker as BrokerModel, Address
from django.db.utils import IntegrityError

from celery_tasks.email.tasks import send_email
from md_sc.config import BROKER_MAP
from md_sc.utils import redis_check_sms_code, get_email_url
from django.forms import model_to_dict


class UsernameCountView(View):

    def get(self, request, username):
        user_count = User.objects.filter(username=username).count()
        if user_count:
            return http.JsonResponse({'code': 4001, 'errmsg': '用户名已存在', 'count': user_count})
        return http.JsonResponse({'code': 0, 'errmsg': 'ok', 'count': user_count})


class MobileCountView(View):

    def get(self, request, mobile):
        user_count = User.objects.filter(mobile=mobile).count()
        if user_count:
            return http.JsonResponse({'code': 0, 'errmsg': '号码已存在', 'count': user_count})
        return http.JsonResponse({'code': 0, 'errmsg': 'ok', 'count': user_count})


class Register(View):

    def post(self, request):
        data = json.loads(request.body.decode())
        sms_code = data.pop('sms_code')

        if not redis_check_sms_code(data.get('mobile'), sms_code):
            return http.JsonResponse({'code': 4005, 'errmsg': '短信验证码失效'})

        if not (data.pop('password2') == data.get('password') and data.pop('allow')):
            return http.JsonResponse({'code': 4005, 'errmsg': '参数不正确'})

        try:
            user = User.objects.create_user(**data)
        except IntegrityError as e:
            return http.JsonResponse({'code': 4000, 'errmsg': '账号或手机已存在'})
        except Exception as e:
            print(e)
            return http.JsonResponse({'code': 5000, 'errmsg': '数据库未知报错'})

        login(request, user)
        return http.JsonResponse({'code': 0, 'errmsg': '创建成功'})


class Login(View):

    def post(self, request):
        data_dict = json.loads(request.body.decode())
        username = data_dict.get('username')
        password = data_dict.get('password')
        remembered = data_dict.get('remembered')

        user = authenticate(request, username=username, password=password)
        if not user:
            return http.JsonResponse({'code': 400, 'errmsg': '用户明明码错误'})

        if remembered:
            request.session.set_expiry(None)
        else:
            request.session.set_expiry(0)

        login(request, user)

        # 绑定三方登录状态
        if access_token := data_dict.get('access_token'):
            redis_conn = get_redis_connection('verify_code')
            uid = redis_conn.get(access_token).decode()
            if uid:
                BrokerModel.objects.create(user=user, name=data_dict.get('broker'), mark=uid)
                redis_conn.delete(access_token)

        response = http.JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.set_cookie('username', user.username, max_age=3600 * 24 * 14)
        return response


class Logout(View):

    def delete(self, request):
        logout(request)
        return http.JsonResponse({'code': 0, 'errmsg': '退出'})


class Broker(View):

    def get(self, request, broker):
        broker_data = BROKER_MAP.get(broker)
        url = broker_data.get('url')
        appkey = broker_data.get('app_id')
        client_secret = broker_data.get('client_secret')
        redirect_uri = broker_data.get('redirect')

        code = request.GET.get('code')
        ret = post(f'{url}client_id={appkey}'
                   f'&client_secret={client_secret}'
                   f'&grant_type=authorization_code'
                   f'&code={code}'
                   f'&redirect_uri={redirect_uri}')
        data = ret.json()
        access_token = data.get('access_token')
        if broker == 'weibo':
            uid = data.get('uid')
        elif broker == 'gitee':
            uid = self._get_user(data.get('access_token'))
        if not (ret.status_code == 200 and data.get('access_token')):
            print(data)
            return http.JsonResponse({'code': 400, 'errmsg': '登录失败'})

        broker_obj = BrokerModel.objects.filter(name=broker, mark=data.get('uid')).first()

        if broker_obj and broker_obj.user:
            login(request, broker_obj.user)
            response = http.JsonResponse({'code': 0, 'errmsg': 'ok'})
            response.set_cookie('username', broker_obj.user.username, max_age=3600 * 24 * 14)
            return response

        redis_conn = get_redis_connection('verify_code')
        redis_conn.setex(access_token, 300, str(uid))
        return http.JsonResponse({'code': 300, 'errmsg': 'ok', 'access_token': access_token})

    def _get_user(self, token):
        url = f'https://gitee.com/api/v5/user?access_token={token}'
        ret = requests.get(url)
        if ret.status_code == 200:
            return ret.json().get('id')


class Authorization(View):

    def get(self, request, broker):
        broker_data = BROKER_MAP.get(broker)
        if broker_data:
            url = f'{broker_data.get("authorize")}' \
                  f'client_id={broker_data.get("app_id")}&' \
                  f'redirect_uri={broker_data.get("redirect")}'
        else:
            return http.JsonResponse(
                {'code': 400,
                 'errmsg': '未知的三方',
                 'login_url': ''}
            )
        return http.JsonResponse(
            {'code': 0,
             'errmsg': 'ok',
             'login_url': url}
        )


class UserView(View):

    def get(self, request):
        """提供个人信息界面"""

        # 获取界面需要的数据,进行拼接

        user = deepcopy(model_to_dict(request.user))
        user.pop('password')

        # 返回响应
        return http.JsonResponse({'code': 0, 'errmsg': 'ok', 'info_data': user})


class EmailView(View):

    def put(self, request):
        email = json.loads(request.body.decode()).get('email')

        if not email:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '缺少email参数'})

        url, token = get_email_url(request.user.id, email)
        send_email.delay(email, url)

        redis_conn = get_redis_connection('session')
        redis_conn.hset(token, mapping={"email": email, "id": request.user.id})

        # 返回响应
        return http.JsonResponse({'code': 0, 'errmsg': '请验证邮箱'})


class EmailVerif(View):

    def put(self, request):
        token = request.GET.get('token')
        redis_conn = get_redis_connection('session')
        try:
            email_url, uid = redis_conn.hmget(token, ['email', 'id'])
            User.objects.filter(id=uid).update(email=email_url.decode(), email_active=True)
        except Exception as e:
            return http.JsonResponse({'code': 400, 'errmsg': '验证失败'})
        return http.JsonResponse({'code': 0, 'errmsg': '请验证邮箱'})


class Addr(View):

    def post(self, request):
        data = json.loads(request.body.decode())

        # 获取地址个数:
        count = Address.objects.filter(user=request.user, is_deleted=False).count()
        # 判断是否超过地址上限：最多20个
        if count >= 20:
            return http.JsonResponse({'code': 400, 'errmsg': '超过地址数量上限'})

        try:
            address = Address.objects.create(**data, user=request.user)
        except Exception as e:
            print(e, type(e))
            return http.JsonResponse({'code': 400, 'errmsg': '参数有误'})

        if not request.user.default_address:
            request.user.default_address = address
            request.user.save()

        return http.JsonResponse({'code': 0, 'errmsg': 'ok', 'address': model_to_dict(address)})


class AddrList(View):

    def get(self, request):
        addrs = Address.objects.filter(user=request.user, is_deleted=False)
        return http.JsonResponse({'code': 0,
                                  'errmsg': 'ok',
                                  'addresses': [model_to_dict(addr) for addr in addrs],
                                  'default_address_id': request.user.default_address.id})


class UpdateAddressView(View):

    def put(self, request, address_id):
        data = json.loads(request.body.decode())

        # 获取地址个数:
        try:
            addr = Address.objects.filter(id=address_id).first()
            if request.user.id == addr.user.id:
                addr = Address.objects.filter(id=address_id).update(**data)
            else:
                # todo 非法用户记录
                raise Exception("别搞老子服务器")
        except Exception as e:
            print(e, type(e))
            return http.JsonResponse({'code': 400, 'errmsg': '参数有误'})
        return http.JsonResponse({'code': 0, 'errmsg': 'ok', 'address': data})

    def delete(self, request, address_id):

        # 获取地址个数:
        try:
            addr = Address.objects.filter(id=address_id).first()
            if request.user.id == addr.user.id:
                addr = Address.objects.filter(id=address_id).update(is_deleted=True)
            else:
                # todo 非法用户记录
                raise Exception("别搞老子服务器")
        except Exception as e:
            print(e, type(e))
            return http.JsonResponse({'code': 400, 'errmsg': '参数有误'})
        return http.JsonResponse({'code': 0, 'errmsg': 'ok'})


class DefaultAddressView(View):
    def put(self, request, address_id):
        try:
            address_ids = request.user.address.values('id')
            if address_id in [i.get('id') for i in address_ids]:
                request.user.default_address_id = address_id
                request.user.save()
            else:
                # todo 非法用户记录
                raise Exception("别搞老子服务器")
        except Exception as e:
            print(e, type(e))
            return http.JsonResponse({'code': 400, 'errmsg': '参数有误'})
        return http.JsonResponse({'code': 0, 'errmsg': '设置默认地址成功', })


class TitleAddressView(View):

    def put(self, request, address_id):
        data = json.loads(request.body.decode())

        try:
            addr = Address.objects.filter(id=address_id).first()
            if request.user.id == addr.user.id:
                addr = Address.objects.filter(id=address_id).update(**data)
            else:
                # todo 非法用户记录
                raise Exception("别搞老子服务器")
        except Exception as e:
            print(e, type(e))
            return http.JsonResponse({'code': 400, 'errmsg': '参数有误'})
        return http.JsonResponse({'code': 0, 'errmsg': 'ok', 'address': data})


class UserPasswordView(View):
    def put(self, request):
        data = json.loads(request.body.decode())
        pwd = data.get('new_password')
        pwd2 = data.get('new_password2')

        # 判断旧密码
        flg = request.user.check_password(data.get('old_password'))
        if not flg:
            return http.JsonResponse({'code': 4000, 'errmsg': '原密码不正确'})

        if pwd != pwd2:
            return http.JsonResponse({'code': 4000, 'errmsg': '密码不一直'})

        try:
            request.user.set_password(pwd)
            request.user.save()
        except Exception as e:
            print(e, type(e))
            return http.JsonResponse({'code': 400, 'errmsg': '参数有误'})

        # 清理状态保持信息
        logout(request)
        response = http.JsonResponse({'code': 0,
                                      'errmsg': 'ok'})

        response.delete_cookie('username')
        return response
